package com.alifi.crm.biz.guess;

import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.List;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import org.springframework.transaction.TransactionStatus;
import org.springframework.transaction.support.TransactionCallback;
import org.springframework.transaction.support.TransactionTemplate;

import com.alibaba.common.lang.StringUtil;
import com.alibaba.common.logging.Logger;
import com.alibaba.common.logging.LoggerFactory;
import com.alifi.crm.dal.enu.States;
import com.alifi.crm.dal.enu.YesOrNo;
import com.alifi.crm.dal.guess.EmployeeGuessDAO;
import com.alifi.crm.dal.guess.EmployeeGuessLogDAO;
import com.alifi.crm.dal.guess.RedEnvelopeCountDAO;
import com.alifi.crm.dal.guess.TransmitLogDAO;
import com.alifi.crm.dal.object.EmployeeGuessDO;
import com.alifi.crm.dal.object.EmployeeGuessLogDO;
import com.alifi.crm.dal.object.RedEnvelopeCountDO;
import com.alifi.crm.dal.object.TransmitLogDO;

@Component("employeeGuessManager")
public class EmployeeGuessManagerImpl implements EmployeeGuessManager{

	@Autowired
	private EmployeeGuessDAO employeeGuessDAO;
	
	@Autowired
	private RedEnvelopeCountDAO redEnvelopeCountDAO;
	
	@Autowired
	private EmployeeGuessLogDAO employeeGuessLogDAO;
	
	@Autowired
	private TransactionTemplate transactionTemplate;
	
	@Autowired
	private TransmitLogDAO transmitLogDAO;
	
	protected static final Logger      logger = LoggerFactory.getLogger(EmployeeGuessManagerImpl.class);
	
	
	@Override
	public EmployeeGuessDO getEmployeeGuess(String employeeNum) {
		if(StringUtil.isBlank(employeeNum)){
			throw new GuessException("employeeNum is null");
		}
		return employeeGuessDAO.selectByEmployeeNum(StringUtil.trim(employeeNum));
	}
	
	@Override
	public Long getCurrentInventoryNum(String dateStr){
		if(StringUtil.isBlank(dateStr)){
			throw new GuessException("dateStr is null");
		}
		RedEnvelopeCountDO countDO = redEnvelopeCountDAO.selectByRedEnvelopDate(dateStr);
		if(countDO==null||countDO.getCurrentInventoryNum()==null){
			return 0L;
		}
		return countDO.getCurrentInventoryNum();
	}


	@Override
	public GuessResult guess(final String employeeNum, final Long guessAmount) {
		try{
			if(employeeGuessDAO.getLockByEmployeeNum(StringUtil.trim(employeeNum))==1){
				return (GuessResult)transactionTemplate.execute(new TransactionCallback(){
					@Override
					public Object doInTransaction(TransactionStatus status) {
						try{
							return guessNoTransaction(employeeNum,guessAmount);
						}
						catch(RuntimeException e){
							logger.error(e);
							throw e;
						}
						catch (Error err) {
							logger.error(err);
							throw err;
						}
					}
				});
			}
			else{
				return GuessResult.没拿到锁;
			}
		}
		finally{
			employeeGuessDAO.releaseLockByEmployeeNum(StringUtil.trim(employeeNum));
		}
	}
	
	private  GuessResult guessNoTransaction(String employeeNum, Long guessAmount){	
		EmployeeGuessDO employeeGuessDO = checkEmployeeGuess(employeeNum,guessAmount);
		EmployeeGuessLogDO employeeGuessLogDO = genEmployeeGuessLogDO(employeeGuessDO,guessAmount);
		
		Long guessTimes = employeeGuessDO.getGuessTimes()+1;   //预设已猜次数,不管猜对猜错，都会算一次。
		int r = guessAmount.compareTo(employeeGuessDO.getRightAmount());
		if(r==0){  //正确
			RedEnvelopeCountDO redEnvelopeCountDO = checkRedEnvelopeCountWithLock();
			GuessResult rightResult = null;
			if(redEnvelopeCountDO.getCurrentInventoryNum()<=0){
				//红包发完，给出提示
				rightResult = equalsNotEnvelopeLogic(guessTimes, employeeNum);
			}
			else if(YesOrNo.正确.equals(redEnvelopeCountDO.getIsRandom())){  //如果设置了随机
				if(Base.isHit(redEnvelopeCountDO.getChance().intValue())){  //随机有红包
					rightResult = equalsLogic(redEnvelopeCountDO,guessTimes, employeeNum);
				}
				else{   //随机没红包
					rightResult = equalsRandomNotEnvelopeLogic(guessTimes, employeeNum);
				}
			}
			else{  // 没设置随机
				rightResult = equalsLogic(redEnvelopeCountDO,guessTimes, employeeNum);
			}
			employeeGuessLogDO.setIsRight(YesOrNo.正确);
			employeeGuessLogDAO.save(employeeGuessLogDO);
			return rightResult;
		}
		else{       //错误
			States states = States.开始;
			if((guessTimes>=Base.maxLimitTimes)&&(!Base.isSmallerEndDate())){
				states = States.结束;
			}
			employeeGuessDAO.updateGuessTimes(guessTimes, employeeNum, YesOrNo.错误,states,null);
			employeeGuessLogDO.setIsRight(YesOrNo.错误);
			employeeGuessLogDAO.save(employeeGuessLogDO);
			
			if(r<0){
				return GuessResult.小了;
			}
			else{
				return GuessResult.大了;
			}
		}
	}
	
	/**
	 * 相等有红包逻辑
	 * @param redEnvelopeCountDO
	 * @param guessTimes
	 * @param employeeNum
	 * @return
	 */
	private GuessResult equalsLogic(RedEnvelopeCountDO redEnvelopeCountDO,Long guessTimes,String employeeNum){
		redEnvelopeCountDO.setCurrentInventoryNum(redEnvelopeCountDO.getCurrentInventoryNum()-1);
		redEnvelopeCountDO.setSendRedEnvelopeNum(redEnvelopeCountDO.getSendRedEnvelopeNum()+1);
		redEnvelopeCountDAO.update(redEnvelopeCountDO);
		employeeGuessDAO.updateGuessTimes(guessTimes, employeeNum, YesOrNo.正确,States.结束,Base.win);
		return GuessResult.相等;
	}
	
	/**
	 * 想等没红包逻辑
	 * @param guessTimes
	 * @param employeeNum
	 * @return
	 */
	private GuessResult equalsNotEnvelopeLogic(Long guessTimes,String employeeNum){
		employeeGuessDAO.updateGuessTimes(guessTimes, employeeNum, YesOrNo.正确,States.开始,null);
		return GuessResult.相等没红包;
	}
	
	/**
	 * 相等随机没红包
	 * @param guessTimes
	 * @param employeeNum
	 * @return
	 */
	private GuessResult equalsRandomNotEnvelopeLogic(Long guessTimes,String employeeNum){
		employeeGuessDAO.updateGuessTimes(guessTimes, employeeNum, YesOrNo.正确,States.开始,null);
		return GuessResult.相等随机没红包;
	}
	
	@Override
	public void addLimitGuessTimes(EmployeeGuessDO employeeGuessDO,String recipient) {
		if(employeeGuessDO==null){
			logger.error("not exist employeeGuessDO. ");
			return;
		}
		if(transmitLogDAO.selectByEmployeeNumAndRecipient(employeeGuessDO.getEmployeeNum(), recipient)!=null){
			return;
		}
		
		Long limitGuessTimes = 0L;
		if(employeeGuessDO.getLimitGuessTimes()>=Base.maxLimitTimes){
			limitGuessTimes = employeeGuessDO.getLimitGuessTimes();
		}
		else{
			limitGuessTimes = employeeGuessDO.getLimitGuessTimes()+1;
		}
		employeeGuessDAO.updateLimitGuessTimes(limitGuessTimes, employeeGuessDO.getEmployeeNum(), employeeGuessDO.getInitTransmitTimes()+1, employeeGuessDO.getActTransmitTimes()+1);
		transmitLogDAO.save(genTransmitLogDO(employeeGuessDO.getEmployeeNum(),recipient));
	}
	
	
	
	
	private TransmitLogDO genTransmitLogDO(String employeeNum,String recipient){
		TransmitLogDO transmitLogDO = new TransmitLogDO();
		transmitLogDO.setEmployeeNum(employeeNum);
		transmitLogDO.setRecipient(recipient);
		return transmitLogDO;
	}

	@Override
	public List<EmployeeGuessLogDO> getEmployeeGuessLogList(String employeeNum) {
		if(StringUtil.isBlank(employeeNum)){
			throw new GuessException("employeeNum is null");
		}
		return employeeGuessLogDAO.selectByEmployeeNum(employeeNum);
	}

	
	
	/**
	 * 生成猜数字记录
	 * @param employeeGuessDO
	 * @param guessAmount
	 * @return
	 */
	private EmployeeGuessLogDO genEmployeeGuessLogDO(EmployeeGuessDO employeeGuessDO,Long guessAmount){
		EmployeeGuessLogDO employeeGuessLogDO = new EmployeeGuessLogDO();
		employeeGuessLogDO.setEmployeeNum(employeeGuessDO.getEmployeeNum());
		employeeGuessLogDO.setGuessAmount(guessAmount);
		employeeGuessLogDO.setRightAmount(employeeGuessDO.getRightAmount());
		return employeeGuessLogDO;
	}
	
	/**
	 * 检查RedEnvelopCount
	 * @param redEnvelopeCountDO
	 */
	private RedEnvelopeCountDO checkRedEnvelopeCountWithLock(){
		String redEnvelopDate = new SimpleDateFormat("yyyyMMdd").format(new Date());
		RedEnvelopeCountDO redEnvelopeCountDO = redEnvelopeCountDAO.selectByRedEnvelopDate(redEnvelopDate);
		if(redEnvelopeCountDO==null){
			throw new SystemException("date error. not exist redEnvelopeCountDO by RedEnvelopDate:"+new SimpleDateFormat("yyyyMMdd").format(new Date()));
		}
//		if(redEnvelopeCountDO.getCurrentInventoryNum()<=0){
//			throw new GuessException("哎呀，真可惜，红包已经发完了~明天再来哟（周一再来哟）");
//		}
		/**
		Long lock = redEnvelopeCountDAO.getLockByRedEnvelopDate(redEnvelopDate);
		if(!new Long(1).equals(lock)){
			throw new SystemException("can't get lock by redEnvelopDate: "+redEnvelopDate);
		}
		*/
		return redEnvelopeCountDAO.selectByIdForUpdate(redEnvelopeCountDO.getId());
	}
	
	/**
	 * 检查并返回EmployeeGuessDO
	 * @param employeeNum
	 * @param guessNum
	 * @return
	 */
	private EmployeeGuessDO checkEmployeeGuess(String employeeNum, Long guessNum){
		if(StringUtil.isBlank(employeeNum)){
			throw new GuessException("employeeNum is null");
		}
		if(guessNum==null){
			throw new GuessException("guessNum is null");
		}
		EmployeeGuessDO employeeDO = employeeGuessDAO.selectByEmployeeNum(StringUtil.trim(employeeNum));
		if(employeeDO==null){
			throw new SystemException("not exist employeeGuessDO.  by employeeNum:"+employeeNum);
		}
		if(States.结束.equals(employeeDO.getStates())){
			throw new GuessException("the states of employeeNum : "+employeeDO.getEmployeeNum()+" has been end");
		}
		if(employeeDO.getGuessTimes() >= employeeDO.getLimitGuessTimes()){
			throw new GuessException("out of LimitGuessTimes. limitGuessTimes: "+employeeDO.getLimitGuessTimes()+".  guessTimes:"+employeeDO.getGuessTimes());
		}
		/**
		Long lock = employeeGuessDAO.getLockByEmployeeNum(StringUtil.trim(employeeNum));
		if(!new Long(1).equals(lock)){
			throw new SystemException("can't get lock by employeeNum: "+employeeNum);
		}
		*/
		return employeeDO;
	}

	@Override
	public RedEnvelopeCountDO getRedEnvelopeCountDO(String dateStr) {
		if(StringUtil.isBlank(dateStr)){
			throw new GuessException("dateStr is null");
		}
		return redEnvelopeCountDAO.selectByRedEnvelopDate(dateStr);
	}

	@Override
	public void comeIn(String employeeNum) {
		if(StringUtil.isNotBlank(employeeNum)){
			employeeGuessDAO.updateStates(States.进入, employeeNum);
		}
	}

}
